package com.gitee.wsl.coroutines.atomic

import com.gitee.wsl.collections.list.LinkedList
import com.gitee.wsl.ext.coroutines.suspendCoroutineWithTimeout
import com.gitee.wsl.ext.list.popOrNull
import com.gitee.wsl.ext.set.popOrNull
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.sync.Mutex
import kotlin.coroutines.resume

class Condition(private val mutex: Mutex) {
     private val waiters = LinkedList<CancellableContinuation<Unit>>()

     suspend fun await() {
          mutex.unlock()
          try {
               suspendCancellableCoroutine<Unit> { cont ->
                    waiters.add(cont)
               }
          } finally {
               mutex.lock()
          }
     }

     //fun await(var1: Long, var3: DateTimeUnit): Boolean

     suspend fun await(timeout: Long): Boolean{
          mutex.unlock()
          var contTemp:CancellableContinuation<Unit>?=null
          try {
               suspendCoroutineWithTimeout<Unit>(timeout) { cont ->
                    waiters.add(cont)
                    contTemp = cont
               }
          }catch(e: TimeoutCancellationException) {
               waiters.remove(contTemp)
               return false
          }finally {
               mutex.lock()
          }
          return true
     }

     fun signal() {
          waiters.popOrNull()?.resume(Unit)
     }

     fun signalAll() {
          while (waiters.isNotEmpty()) {
               waiters.popOrNull()?.resume(Unit)
          }
     }
}

fun Mutex.newCondition() = Condition(this)